import { forEach, get, isEmpty, isString, isUndefined, uniqueId } from 'lodash-es';
import * as devices from './device/__all__';

/**
 * Types
 */
import type { DeviceManagerType, PropsType } from './typings';
// 利用原型链模式进行实现：
import { prototype, prototypeCondition, prototypeGroup } from './core/prototype';

import DeviceManager from './core';
import { common } from './core/common';
import subscribe from './core/subscribe';

/**
 * Common将当前的DeviceManager对象挂到对象中，装饰器模式实现
 */
common(DeviceManager);

/**
 * Device
 */
forEach(devices, (device) => {
    // 使用示例：new DeviceManager.Light();
    DeviceManager[device.name] = function (opt: PropsType) {
        if (!(this instanceof DeviceManager[device.name])) {
            throw new Error(`DeviceManager.${device.name} 必须通过 new 实例化对象`);
        }

        return create.call(DeviceManager, device, opt);
    };

    window[device.name] = function (opt: PropsType) {
        if (!(this instanceof DeviceManager[device.name])) {
            throw new Error(`DeviceManager.${device.name} 必须通过 new 实例化对象`);
        }

        return create.call(DeviceManager, device, opt);
    };

    // 使用示例：DeviceManager.createLight();
    DeviceManager[`create${device.name}`] = function (opt: PropsType) {
        if (this instanceof DeviceManager[device.name]) {
            throw new Error(`DeviceManager.${device.name} 不能通过 new 实例化对象`);
        }

        return create.call(DeviceManager, device, opt);
    };

    // 使用示例：DeviceManager.getLight();
    DeviceManager[`get${device.name}`] = function (opt: PropsType) {
        if (this instanceof DeviceManager[device.name]) {
            throw new Error(`DeviceManager.${device.name} 不能通过 new 实例化对象`);
        }

        this.warn(`方法 get${device.name} 已废弃，请使用 create${device.name} 代替`);

        return create.call(DeviceManager, device, opt);
    };
});

/**
 * Events
 */
/**
 * 创建设备实例
 */
function create(this: DeviceManagerType, device: any, opt: PropsType) {
    /**
     * 参数
     */
    if (isString(opt) || isUndefined(opt)) {
        opt = { name: opt };
    }

    /**
     * 设备：绑定设备
     */
    const deviceBind = get(window, 'JeeWeb.deviceBind', get(window, 'JeeWeb.TargetDeviceList', []));

    if (deviceBind[this.deviceInstance.length]) {
        const { devices: to, ...device } = deviceBind[this.deviceInstance.length];
        opt.device = device;
        // TODO：to有可能是数组或事对象或undefined，如果to对象：单一，数组：多个群组，
        opt.to = device.type === 'Single' ? to[0] : to;

        /**
         * 兼容代码：如果是undefined，做一下如果数据结果老的，做一下兼容。
         */
        if (isUndefined(to)) {
            opt.to = device;
        }
    }

    /**
     * 创建设备实例
     */
    let instance = new device(opt);

    const categoryCode = instance.categoryCode;
    const categoryName = instance.categoryName;

    /**
     * 原型链，原型链模式和装饰器模式实现一下挂载对象实例
     */
    prototype(instance);

    /**
     * 群组设备
     */
    if (opt.group === true) {
        prototypeGroup(instance);
    }

    /**
     * 条件设备
     */
    if (opt.condition === true) {
        prototypeCondition(instance);
    }

    /**
     * 可选设备
     */
    if (opt.optional === true && isEmpty(opt.to)) {
        instance = null;
    }

    /**
     * 实例数组
     */
    this.deviceInstance.push({
        instance,
        device: opt.device,
        devices: opt.to,
    });

    /**
     * 扫描数组
     */
    this.deviceScan.push({
        categoryAlias: device.name,
        categoryCode,
        categoryName,
        name: opt.name,
        type: opt.group ? 'Group' : 'Single',
        condition: !!opt.condition,
        optional: !!opt.optional,
    });

    /**
     * 兼容代码
     */
    const deviceMaps: Record<string, any> = {};

    if (window.checkDevive === undefined) {
        window.checkDevive = [];
    }

    window.checkDevive.push({
        deviceArr: [],
        deviceName: device.name,
        name: opt.name,
        productId: categoryCode,
    });

    window.checkDevive.forEach((item: any) => {
        if (!deviceMaps[item.productId]) {
            deviceMaps[item.productId] = [];
        }

        deviceMaps[item.productId].push({
            deviceId: `-2${item.productId + uniqueId().padStart(9, '0')}`,
            deviceName: item.deviceName,
        });
    });

    window.checkDevive.forEach((item: any) => {
        item.deviceArr = deviceMaps[item.productId];
    });

    /**
     * 返回设备实例
     */
    return instance;
}

/**
 * Subscribe
 */
let _JeeWeb = window.JeeWeb;
// 将subcribe的内容订阅函数，赋值到_subscribe
let _subscribe = _JeeWeb?.subscribe || _JeeWeb?.onReceive;

/**
 * 将DeviceManager对象绑定到全局，将DeviceManager对象绑定到subcribe对象上，
 * 其实这里将函数(subscribe.bind(DeviceManager))放入_subscribe()中；
 */
_subscribe?.(subscribe.bind(DeviceManager));

if (!_JeeWeb) {
    Object.defineProperty(window, 'JeeWeb', {
        configurable: true,
        enumerable: true,
        get() {
            return _JeeWeb;
        },
        set(value) {
            _JeeWeb = value;
            _subscribe = _JeeWeb?.subscribe || _JeeWeb?.onReceive;

            _subscribe?.(subscribe.bind(DeviceManager));
        },
    });
}

window.DeviceManagerSDK = function () {
    // 为了兼容老平台的包：window.DeviceManagerSDK
    // 每次挂载DeviceManager的时候，将全局的DeviceManager的对象重置一下
    DeviceManager.reset();

    return DeviceManager;
};

export default DeviceManager;
